require "yaml"

module PagePack

  def self.config
    @@config ||= PagePack::Configuration.new
  end

  class Configuration
    attr_accessor :config_file_path,
                  :javascripts_generate_path,
                  :stylesheets_generate_path,
                  :file_version
    
    def initialize
      @config_file_path = "#{RAILS_ROOT}/config/page_pack.yml"
      @javascripts_generate_path = "page_pack_generated"
      @stylesheets_generate_path = "page_pack_generated"
      @file_version = 0
    end
  end

end

class ApplicationController < ActionController::Base

  # XXX
  # Including ActionView::Helpers in ActionController::Base is definitely not a good idea.
  # But here I want to use "javascript_include_tag" in controllers to generate certain <script/> tags
  # and insert them into response.body. I've tried to implement something like "javascript_include_tag" myself
  # but there's no simple way to do this while remains completely compatible with rails' own implementation.
  # So I included these two ActionView::Helpers here, hopefully this won't cause any problems
  include ActionView::Helpers::TagHelper, ActionView::Helpers::AssetTagHelper

  hide_action :insert_javascript_file

  # Use "insert_javascript_file" as a after_filter to add <script/> tags to response.body.
  after_filter :insert_javascript_file

  @@page_pack_js_config = nil

  def insert_javascript_file
    # TODO
    # Allow users to config "Content-Type" themselves.
    return unless response.headers["Content-Type"] == "text/html"
    # XXX
    # This is for the included ActionView::Helpers because they need @controller
    # which references to the current controller.
    @controller = self
    init_page_pack if @@page_pack_js_config.nil? or not RAILS_ENV == "production"
    javascript_files = []
    javascript_files << @@page_pack_js_config["base"].split if @@page_pack_js_config.has_key?("base") and not @@page_pack_js_config["base"].blank?
    javascript_files << @@page_pack_js_config[controller_name][action_name].split if @@page_pack_js_config.has_key?(controller_name) and @@page_pack_js_config[controller_name].has_key?(action_name) and not @@page_pack_js_config[controller_name][action_name].blank?
    javascript_tags = []
    javascript_files.flatten.each do |javascript_file|
      javascript_file = :defaults if javascript_file == "$$defaults"
      javascript_tags << javascript_include_tag(javascript_file)
    end
    if RAILS_ENV == "production"
      packed_js_content = ""
      packed_js_file_path = "#{PagePack.config.javascripts_generate_path}/#{controller_name}.#{action_name}_#{PagePack.config.file_version}.js"
      unless File.exist?("#{RAILS_ROOT}/public/javascripts/#{packed_js_file_path}")
	javascript_tags.collect { |item| item.match(/src="(.*.js)\??\d*"/)[1] }.each do |file_path|
          packed_js_content << IO.read("#{RAILS_ROOT}/public#{file_path}")
        end
        File.open("#{RAILS_ROOT}/public/javascripts/#{packed_js_file_path}", "w") { |file| file.puts packed_js_content } unless packed_js_content.blank?
        end
        javascript_tags.clear << javascript_include_tag(packed_js_file_path)
      end
    # FIXME matching should ignore character case.
    response.body.insert(response.body.downcase.match(/<\/body>\s*<\/html>\s*$/).begin(0), javascript_tags.join("\n") << "\n")
  end

  # load page_pack's javascript and css configuration files.
  # In production mode this will be called only once while in other modes this will
  # be called every time some html template is rendered.
  def init_page_pack
    File.open(File.expand_path(PagePack.config.config_file_path)) do |f|
      @@page_pack_js_config = YAML::load(f)
    end
    Dir.entries("#{RAILS_ROOT}/public/javascripts/#{PagePack.config.javascripts_generate_path}").each { |item| File.delete("#{RAILS_ROOT}/public/javascripts/#{PagePack.config.javascripts_generate_path}/#{item}") } if RAILS_ENV == "production"
    PagePack.config.file_version = PagePack.config.file_version + 1
  end

end